package xj.graph2d.app.prop;

import java.awt.Insets;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.UIManager;

import xj.app.DrawTool;
import xj.graph2d.DrawCanvas;
import xj.graph2d.DrawShape;
import xj.graph2d.GraphDocument;
import xj.graph2d.ModelListener;
import xj.graph2d.SimpleDrawDocument;
import xj.graph2d.SimpleDrawView;
import xj.graph2d.app.DrawApp;
import xj.graph2d.app.resources.Style;
import xj.graph2d.graph.GraphNode;
import xj.graph2d.tools.MultiPointTool;
import xj.graph2d.tools.PointTool;
import xj.meta.ModelElement;

public abstract class ModelPropertyField {

  protected ModelPropertyField() {
    this(null, null, null);
  }

  protected ModelPropertyField(String displayName) {
    this(null, displayName, null);
  }

  protected ModelPropertyField(String fieldName, String displayName) {
    this(fieldName, displayName, null);
  }

  protected ModelPropertyField(String fieldName, String displayName,
			       JComponent editor) {
    this.fieldName = fieldName;
    this.displayName = displayName;
    this.editor = editor;
  }

  public String getFieldName() {
    return fieldName;
  }

  public String getDisplayName() {
    return displayName;
  }

  public JComponent getEditor() {
    return editor;
  }

  public ModelElement getModel() {
    return model;
  }

  public void setModel(ModelElement model) {
    this.model = model;
    updateTips();
  }

  public DrawShape getShape() {
    return shape;
  }

  public void setShape(DrawShape shape) {
    this.shape = shape;
  }

  public void setEditable(boolean b) {
    editable = b;
    if (editor != null) {
      editor.setEnabled(b);
    }
  }

  public boolean isEditable() {
    return editable;
  }

  public void setMain(DrawApp main) {
    this.main = main;
  }

  public Object getModelValue() {
    if (debug)
      System.out.println("ModelPropertyField.getModelValue() model=" + model);

    if (model != null && fieldName != null) {
      try {
	Class cls = model.getClass();
	PropertyDescriptor prop = new PropertyDescriptor(fieldName, cls);
	Method read = prop.getReadMethod();
	return read.invoke(model);
	// Field f = cls.getField(fieldName);
	// return f.get(model);
      } catch (IntrospectionException e) {
	e.printStackTrace();
      } catch (InvocationTargetException e) {
	e.printStackTrace();
      } catch (IllegalAccessException e) {
	e.printStackTrace();
      }
    }
    return null;
  }

  public void setModelValue(Object value) {
    if (debug) 
      System.out.println("ModelPropertyField.setModelValue() model=" + model + " value=" + value);

    if (model != null && fieldName != null) {
      try {
	Class cls = model.getClass();
	PropertyDescriptor prop = new PropertyDescriptor(fieldName, cls);
	Method write = prop.getWriteMethod();
	write.invoke(model, value);
	// Field f = cls.getField(fieldName);
	// f.set(model, value);
      } catch (IntrospectionException e) {
	e.printStackTrace();
      } catch (InvocationTargetException e) {
	e.printStackTrace();
      } catch (IllegalAccessException e) {
	e.printStackTrace();
      }
    }
  }

  protected void setEditor(JComponent editor) {
    this.editor = editor;
  }

  protected void updateTips() {
  }

  protected void updateShape() {
    if (debug) 
      System.out.println("ModelPropertyField.updateShape() @1 editingMode=" + editingMode);

    if (shape != null &&
	editingMode) {
      ModelListener mlistener = shape.getModelListener();
      if (mlistener != null) {
	mlistener.updateShape();
	SimpleDrawView view = main.getView();
	DrawCanvas canvas = view.getCanvas();
	SimpleDrawDocument doc = main.getDoc();
	if (doc instanceof GraphDocument && 
	    shape instanceof GraphNode) {
	  DrawTool tool = view.getCurrentTool();
	  if (tool instanceof PointTool) {
	    ((PointTool) tool).layoutGraphEdgesAdjacentToCurrentNode();
	  } else if (tool instanceof MultiPointTool) {
	    ((MultiPointTool) tool).getPointTool().layoutGraphEdgesAdjacentToCurrentNode();
	  }
	}
	// canvas.repaintShape(shape);
	canvas.repaint();
	doc.shapeChanged(shape);
      }
    }

    if (debug) 
      System.out.println("ModelPropertyField.updateShape() @2");
  }

  public void setEditingMode(boolean b) { 
    if (debug) 
      System.out.println("ModelPropertyField.setEditingMode() " + b);

    editingMode = b;
  }

  abstract public void updateEditorValue();

  abstract public void updateModelValue();

  protected String fieldName;

  protected String displayName;

  protected JComponent editor;

  protected ModelElement model;

  protected DrawShape shape;

  protected DrawApp main;

  protected boolean editable = true;

  protected boolean editingMode = true;

  protected static boolean debug = false; 

  protected static JButton makeEditButton(String text) {
    JButton editButton = new JButton(text);
    editButton.setFont(Style.font);
    editButton.setMargin(new Insets(0, 0, 0, 0));

    // Mac customization
    String osname = System.getProperty("os.name").toLowerCase();
    if (osname.indexOf("mac") != -1) {
      editButton.setBackground(UIManager.getColor("button"));
    }
    return editButton;
  }

}
